library ieee;
use ieee.std_logic_1164.all;

entity multplier is
	port (
		clk, reset, start, setMultiplicand, setMultiplier : in bit;
		dataInExternal : in bit_vector(31 downto 0);
		done : out bit;
		product : out bit_vector(63 downto 0)
	);
end entity multplier;


architecture Structural of multplier is

--Declarations of the different blocks within the multiplier

	component controllerBlock	
		port (
			reset, start, setMultiplicand, setMultiplier, overFlow, clk: in bit;
			clr, regmulti, enCtr, shift, done : out bit;
			holdShift, enLoad, sumLoad : out bit
		);		
	end component;

	component Counter4 is
        port (
                clk : in bit;
                hold_al : in bit; -- active low
                clr_al : in bit;
                overFlow : out bit;
                count : out bit_vector(5 downto 0)
        );
     end component;
	
	component ShiftRegister32
		port (
			clk, clr, load, hold, serialIn : in bit;
			inVec : in bit_vector(31 downto 0);
			outVec : out bit_vector(31 downto 0)
		);		
	end component;
	
	component selectBlock
		port (
			Din : in bit_vector(31 downto 0);
			S : in bit_vector(1 downto 0);
			Dout : out bit_vector(31 downto 0);
			Carry : out bit
		);
	end component;
	
	component productReg is
		port (
			H_in, L_in : in bit_vector(31 downto 0);
			clk, clr, H_load, L_load, H_Hold, L_Hold : in bit;
			H_out, L_out : out bit_vector(31 downto 0);
			a_1: out bit
		);
	end component;
	
	component fullAdder32
		port(
			A, B : in bit_vector(31 downto 0);
			Cin : in bit;
			Sum : out bit_vector(31 downto 0);
			Cout : out bit
		);
	end component;
	
	for all : controllerBlock use entity work.controllerBlock(rtl);
	for all : Counter4 use entity work.Counter4(dataflow);
	for all : ShiftRegister32 use entity work.ShiftRegister32(STRUCTURAL);
	for all : selectBlock use entity work.selectBlock(STRUCTURAL);
	for all : productReg use entity work.productReg(STRUCTURAL);
	for all : fullAdder32 use entity work.fullAdder32(STRUCTURAL);
	
	signal resetIn, startIn, setMultiplicandIn, setMultiplierIn, overFlow, 
			clkIn, clr, regmulti, enCtr, shift, doneOut, holdShift, 
				enLoad, carry, lowestBitProduct, notClr1,notEnLoad, p_sumLoad : bit;
	signal a0a_1 : bit_vector (1 downto 0);
	signal dataOutSR, dataOutSelect, highBitsProduct, lowBitsProduct, 
			adderResult, dataIn : bit_vector (31 downto 0);
	signal gnd, clr1 : bit := '0';
	
begin

  dataIn <= dataInExternal;
	a0a_1(0) <= lowestBitProduct;
	a0a_1(1) <= lowBitsProduct(0);
	resetIn <= reset;
	startIn <= start;
	setMultiplicandIn <= setMultiplicand;
	setMultiplierIn <= setMultiplier;
	clkIn <= clk;
	done <= doneOut;
	clr1 <= clr after 10 ns;
	notClr1 <= not clr1 after 20 ns;
	notEnLoad <= not enLoad after 20 ns;
	
	CNTRLLR : controllerBlock port map (resetIn, startIn, setMultiplicandIn, setMultiplierIn, overFlow, clkIn,
				 clr, regmulti, enCtr, shift, doneOut,
				 	holdShift, enLoad, p_sumLoad);
					
	--may need to decrease the counter to 5 bits
	COUNTER : Counter4 port map(clkIn, enCtr, Clr1, overFlow);
	
	--to load: hold = 0, load = 1
	--hold disables the load function
	--Hold needs to be not Load inorder to allow for bits to be loaded and not shifted
	SHFT : ShiftRegister32 port map (clkIn, notClr1, EnLoad, notEnLoad, '0', 
				dataIn, dataOutSR);
	
	SLCT : selectBlock port map(dataOutSR, a0a_1, dataOutSelect, carry);
	
	--H_Load, L_Load are active high
	--clr and hold are active low
	--loads must be off to clear or shift	
	PRDCTREG : productReg port map (adderResult, dataIn, 
				clkIn, notClr1, p_sumLoad, regmulti, Shift, holdShift, 
					highBitsProduct, lowBitsProduct, lowestBitProduct);
	
	FULLA32 : fullAdder32 port map (dataOutSelect, highBitsProduct, carry, 
				adderResult, gnd);
	
	product(63 downto 32) <= highBitsProduct;
	product(31 downto 0) <= lowBitsProduct;

end architecture Structural;
